﻿using Abp.Authorization;
using Abp.Domain.Repositories;
using Abp.Domain.Uow;
using Abp.Runtime.Session;
using Abp.UI;
using Mt.Site.Application.Dto.ManualSynchorize;
using Mt.Site.Application.Navigation.Dto.Sync;
using Mt.Site.Core.Navigations;
using Mt.Site.Core.Navigations.Entities;
using Mt.Site.Core.Navigations.Permissions;
using Mt.Site.Core.Navigations.Values;
using Mt.Site.Core.Synchronization;
using Mt.Site.Core.Synchronization.Data;
using Mt.Site.Core.Synchronization.Navigations;
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Transactions;

namespace Mt.Site.Application.Navigation
{
    public class NavigationSyncAppService : MtSiteAppServiceBase, INavigationSyncAppService
    {
        private readonly IMenuManualSyncManager _menuManualSyncManager;
        private readonly IMenuManager _menuManager;

        private readonly IRepository<Menu, Guid> _menuRepository;

        private readonly ISynchronizationHelper _synchronizationHelper;

        public NavigationSyncAppService(
            IMenuManager menuManager,
            IMenuManualSyncManager menuManualSyncManager,
            IRepository<Menu, Guid> menuRepository,
            ISynchronizationHelper synchronizationHelper)
        {
            _menuManager = menuManager;
            _menuManualSyncManager = menuManualSyncManager;

            _menuRepository = menuRepository;
            _synchronizationHelper = synchronizationHelper;
        }

        [AbpAuthorize(MenuPermissions.Pages_Tenant_Menus_Create, MenuPermissions.Pages_Tenant_Menus_Edit)]
        public async Task<GetMenuTreeOutput> GetMenuTreeFromParentSite()
        {
            using (CurrentUnitOfWork.DisableFilter(
                AbpDataFilters.MayHaveTenant,
                AbpDataFilters.MustHaveTenant,
                MtSiteConsts.AbpDataFilters.MustHaveLanguage))
            {
                var motherSiteInfo = _synchronizationHelper.GetMotherSiteInfo(AbpSession.GetTenantId(), AbpSession.CultureName());
                if (motherSiteInfo == null)
                {
                    return null;
                }

                var items = await _menuManager.GetMenuTree(motherSiteInfo.MotherTenantId, motherSiteInfo.MotherLanguage);
                return new GetMenuTreeOutput
                {
                    Items = items.Select(item => ObjectMapper.Map<MenuItemDto>(item)).ToList(),
                    MotherTenantId = motherSiteInfo.MotherTenantId,
                    MotherLanguage = motherSiteInfo.MotherLanguage,
                    TenantDisplayName = motherSiteInfo.TenantDisplayName
                };
            }
        }

        [AbpAuthorize(MenuPermissions.Pages_Tenant_Menus_Create, MenuPermissions.Pages_Tenant_Menus_Edit)]
        public async Task ManualSynchorize(MenuSynInput input)
        {
            using (CurrentUnitOfWork.DisableFilter(
                AbpDataFilters.MayHaveTenant,
                AbpDataFilters.MustHaveTenant,
                MtSiteConsts.AbpDataFilters.MustHaveLanguage))
            {
                foreach (var id in input.RequiredMenuItems)
                {
                    await ManualSynchorizeOneByOne(id, input.FromLanguage);
                }
            }
        }

        private async Task ManualSynchorizeOneByOne(Guid id, string language)
        {
            using (var uow = UnitOfWorkManager.Begin(new UnitOfWorkOptions
            {
                Scope = TransactionScopeOption.RequiresNew
            }))
            {
                var currentEntity = await _menuRepository.FirstOrDefaultAsync(id);
                if (currentEntity != null)
                {
                    var toId = await _menuManualSyncManager.CreateOrUpdateMenuManualSync(
                        new CreateOrUpdateSynchorizeStore
                        {
                            Id = id,
                            TargetLanguage = AbpSession.CultureName(),
                            ToTenantId = AbpSession.GetTenantId()
                        }, language);

                    if (toId == Guid.Empty)
                    {
                        //Logger.Debug($"栏目手动同步失败，tenantId: {currentEntity.TenantId},menuId:{id}");
                    }
                }
                await uow.CompleteAsync();
            }
        }

        [AbpAuthorize(MenuPermissions.Pages_Tenant_Menus_StyleAndScript)]
        public async Task<ManualSyncOut> ManualSynchorizeStyles(ManualSyncInput input)
        {
            using (CurrentUnitOfWork.DisableFilter(
                AbpDataFilters.MayHaveTenant,
                AbpDataFilters.MustHaveTenant,
                MtSiteConsts.AbpDataFilters.MustHaveLanguage))
            {
                var motherSiteInfo = _synchronizationHelper.GetMotherSiteInfo(AbpSession.GetTenantId(), AbpSession.CultureName());
                if (motherSiteInfo == null)
                {
                    throw new UserFriendlyException(L("NoMotherSite"));
                }

                var currentMenuEntity = await _menuRepository.FirstOrDefaultAsync(input.Id);
                if (currentMenuEntity == null)
                {
                    throw new UserFriendlyException(L("NoSourceDataInMotherSite"));
                }

                var motherMenuEntity = await _menuRepository.FirstOrDefaultAsync(
                    item => item.AuxiliaryId == currentMenuEntity.AuxiliaryId && item.TenantId == motherSiteInfo.MotherTenantId);
                if (motherMenuEntity == null)
                {
                    throw new UserFriendlyException(L("NoSourceDataInMotherSite"));
                }
                var syncResult = await _menuManualSyncManager.StylesAndScriptsSyncManualSync(
                        new ManualSyncMenuStylesArgs
                        {
                            ToTenantId = AbpSession.GetTenantId(),
                            FromMenuId = motherMenuEntity.Id,
                            ToMenuId = currentMenuEntity.Id,
                            TargetLanguage = AbpSession.CultureName()
                        });

                if (syncResult)
                {
                    return new ManualSyncOut
                    {
                        SyncResult = true
                    };
                }
            }
            return new ManualSyncOut
            {
                SyncResult = false
            };
        }
    }
}
